﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using RAP.Framework.Libary.Utils;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
using System.Collections.Concurrent;

namespace RAP.Framework.Libary.Lock
{
    #region 全局锁
    /// <summary>
    /// 全局锁静态对象
    /// </summary>
    public class GlobalLocks : IDisposable
    {
        /// <summary>
        /// 最大的并发锁的并发锁数量，默认1024个
        /// </summary>
        public static int MAX_LOCKS_LOCK_NUMBER = 1024;

        #region private static
        private static IDictionary _globalLocks = new ConcurrentDictionary<string, object>( 2, MAX_LOCKS_LOCK_NUMBER );
        private static object[ ] _globalLocksLock = null;
        private static GlobalLocks _instance = new GlobalLocks( );
        #endregion private static

        private GlobalLocks( )
        {
            //默认1024个并发锁的并发锁
            _globalLocksLock = new object[ MAX_LOCKS_LOCK_NUMBER ];
            for ( int i = 0; i < MAX_LOCKS_LOCK_NUMBER; i++ )
            {
                _globalLocksLock[ i ] = new object( );
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object this[ string key ]
        {
            get
            {
                object lockObj = _globalLocks[ key ];
                if ( lockObj == null )
                {
                    int globalLockIndex = Math.Abs( key.GetHashCode( ) ) % _globalLocksLock.Length;//相同Hash值的键使用同一个_globalLocksLock来创建全局锁
                    lock ( _globalLocksLock[ globalLockIndex ] )
                    {
                        lockObj = _globalLocks[ key ];
                        if ( lockObj == null )
                        {
                            lockObj = _globalLocks[ key ] = new object( );
                        }
                    }
                }
                return lockObj;
            }
        }

        public void Dispose( )
        {
            _globalLocks.Clear( );
        }

        #region Static Methods
        /// <summary>
        /// 获取单例实例
        /// </summary>
        public static GlobalLocks Instance
        {
            get
            {
                return _instance;
            }
        }

        /// <summary>
        /// 获取指定键的lock对象
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static object Get( string key )
        {
            return _instance[ key ];
        }

        /// <summary>
        /// 异步方式获取一个LockObject对象
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static async Task<object> GetAsync( string key )
        {
            return await Task.FromResult( _instance[ key ] );
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="lockBody"></param>
        /// <returns></returns>
        public static T Lock<T>( string key, Func<T> lockBody )
        {
            if ( key.IsNullOrEmpty( ) )
            {
                throw new NullReferenceException( "lock key can't be null." );
            }
            lock ( GlobalLocks.Instance[ key ] )
            {
                return lockBody( );
            }
        }

        /// <summary>
        /// 在异步管道模式中同步执行指定Func
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="lockBody"></param>
        /// <returns></returns>
        public static async Task<T> LockAsync<T>( string key, Func<T> lockBody )
        {
            return await Task.Run<T>( ( ) =>
            {
                return GlobalLocks.Lock<T>( key, lockBody );
            } );
        }

        /// <summary>
        /// 执行指定键的锁定操作
        /// </summary>
        /// <param name="key"></param>
        /// <param name="lockBody"></param>
        public static void Lock( Action lockBody, [CallerMemberName] string key = null )
        {
            if ( key.IsNullOrEmpty( ) )
            {
                lockBody( );
            }
            else
            {
                lock ( GlobalLocks.Instance[ key ] )
                {
                    lockBody( );
                }
            }
        }

        /// <summary>
        /// 在异步管道模式中同步执行指定Action
        /// </summary>
        /// <param name="lockBody"></param>
        /// <param name="key">默认为调用函数的名称</param>
        /// <returns></returns>
        public static async Task LockAsync( Action lockBody, [CallerMemberName] string key = null )
        {
            await Task.Run( ( ) =>
            {
                if ( key.IsNullOrEmpty( ) )
                {
                    lockBody( );
                }
                else
                {
                    lock ( GlobalLocks.Instance[ key ] )
                    {
                        lockBody( );
                    }
                }
            } );
        }

        /// <summary>
        /// 执行指定键的锁定操作
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="checkLock">检测键的函数</param>
        /// <param name="lockBody">执行锁定的代码块</param>
        public static GlobalLocks Lock( string key, Func<bool> checkLock, Action lockBody )
        {
            if ( !checkLock( ) )
            {
                lock ( GlobalLocks.Instance[ key ] )
                {
                    try
                    {
                        if ( !checkLock( ) )
                        {
                            lockBody( );
                        }
                    }
                    catch ( Exception ex )
                    {
                        throw ex;
                    }
                }
            }
            checkLock = null;
            lockBody = null;
            return _instance;
        }

        /// <summary>
        /// 在异步管道模式中同步执行指定Action
        /// </summary>
        /// <param name="key">同步锁定的Key</param>
        /// <param name="checkLock">检测是否执行Action的判断函数</param>
        /// <param name="lockBody">要进行同步锁定执行的Action</param>
        /// <returns></returns>
        public static async Task<GlobalLocks> LockAsync( string key, Func<bool> checkLock, Action lockBody )
        {
            return await Task.Run<GlobalLocks>( ( ) =>
            {
                return GlobalLocks.Lock( key, checkLock, lockBody );
            } );
        }

        /// <summary>
        /// 无条件锁
        /// </summary>
        /// <param name="key"></param>
        /// <param name="lockBody"></param>
        /// <returns></returns>
        public static GlobalLocks Lock( string key, Action lockBody )
        {
            lock ( GlobalLocks.Instance[ key ] )
            {
                try
                {
                    lockBody( );
                }
                catch ( Exception ex )
                {
                    throw ex;
                }
            }
            return _instance;
        }

        /// <summary>
        /// 在异步管道模式中同步执行指定Action
        /// </summary>
        /// <param name="key">同步锁定的Key</param>
        /// <param name="lockBody">要进行同步锁定执行的Action</param>
        /// <returns></returns>
        public static async Task<GlobalLocks> LockAsync( string key, Action lockBody )
        {
            return await Task.Run<GlobalLocks>( ( ) =>
            {
                return GlobalLocks.Lock( key, lockBody );
            } );
        }

        /// <summary>
        /// 根据LockScope来进行同步锁定执行指定Action
        /// </summary>
        /// <param name="lockRequest"></param>
        /// <returns></returns>
        public static GlobalLocks Lock( LockScope lockRequest )
        {
            return GlobalLocks.Lock( lockRequest.Key, lockRequest.CheckLock, lockRequest.LockBody );
        }

        /// <summary>
        /// 通过异步管道模式和LockScope来进行同步锁定执行指定Action
        /// </summary>
        /// <param name="lockRequest"></param>
        /// <returns></returns>
        public static async Task<GlobalLocks> LockAsync( LockScope lockRequest )
        {
            return await Task.Run<GlobalLocks>( ( ) =>
            {
                return GlobalLocks.Lock( lockRequest );
            } );
        }

        /// <summary>
        /// 创建一个指定Key的LockScope
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static LockScope Lock( string key )
        {
            return new LockScope( ) { Key = key };
        }
        #endregion Static Methods

    }
    #endregion
}
